#!/bin/sh /etc/rc.common

START=99
STOP=15
USE_PROCD=1
NAME=xray_core

FIREWALL_INCLUDE="/usr/share/xray/firewall_include.ut"

setup_firewall() {
    ip rule add fwmark 251 lookup 251
    ip route add local default dev lo table 251
    ip -6 rule add fwmark 251 lookup 251
    ip -6 route add local default dev lo table 251

    logger -st xray[$$] -p4 "Generating firewall4 rules..."
    /usr/bin/utpl ${FIREWALL_INCLUDE} > /var/etc/xray/firewall_include.nft

    logger -st xray[$$] -p4 "Triggering firewall4 restart..."
    /etc/init.d/firewall restart
}

flush_firewall() {
    ip rule del fwmark 251 lookup 251
    ip route del local default dev lo table 251
    ip -6 rule del fwmark 251 lookup 251
    ip -6 route del local default dev lo table 251

    logger -st xray[$$] -p4 "Flushing firewall4 rules..."
    rm -f /var/etc/xray/firewall_include.nft

    logger -st xray[$$] -p4 "Triggering firewall4 restart..."
    /etc/init.d/firewall restart
}

uci_get_by_type() {
    local ret=$(uci get ${NAME}.@$1[0].$2 2>/dev/null)
    echo ${ret:=$3}
}

log_procd_set_param() {
    local type="$1"
    shift
    logger -st xray[$$] -p4 "Using procd_set_param $type" "$@"
}

start_xray() {
    logger -st xray[$$] -p4 "Starting Xray from $1"
    procd_open_instance
    procd_set_param respawn 1 1 0
    procd_set_param command $1
    procd_append_param command run
    procd_append_param command -confdir
    procd_append_param command /var/etc/xray

    local rlimit_nofile
    if [ -s /usr/share/xray/rlimit_nofile ] ; then
        rlimit_nofile="nofile=""$(cat /usr/share/xray/rlimit_nofile)"
    fi

    local rlimit_data
    if [ -s /usr/share/xray/rlimit_data ] ; then
        rlimit_data="data=""$(cat /usr/share/xray/rlimit_data)"
    fi

    # this param passing method is just so fucking weird
    if [ -z "${rlimit_nofile}" ] ; then
        if [ ! -z "${rlimit_data}" ]; then
            log_procd_set_param limits "${rlimit_data}"
            procd_set_param limits "${rlimit_data}"
        fi
    else
        if [ -z "${rlimit_data}" ]; then
            log_procd_set_param limits "${rlimit_nofile}"
            procd_set_param limits "${rlimit_nofile}"
        else
            log_procd_set_param limits "${rlimit_data}" "${rlimit_nofile}"
            procd_set_param limits "${rlimit_data}" "${rlimit_nofile}"
        fi
    fi

    procd_set_param env XRAY_LOCATION_ASSET=/usr/share/xray
    procd_set_param stdout 1
    procd_set_param stderr 1
    procd_set_param file /etc/config/xray
    procd_set_param pidfile /var/run/xray.pid
    procd_close_instance
}

gen_config_file() {
    rm -f /etc/nftables.d/99-xray.nft /var/etc/xray/*
    for gen_config_file_attempt in 1 2 3 4 5; do
        logger -st xray[$$] -p4 "Generating Xray configuration files (attempt ${gen_config_file_attempt})..."
        /usr/bin/ucode /usr/share/xray/gen_config.uc > /var/etc/xray/config.json
        if [ -s /var/etc/xray/config.json ] ; then
            break
        else
            sleep 1
        fi
    done
    local custom_config=$(uci_get_by_type general custom_config)
    [ ! "${#custom_config}" == "0" ] && echo ${custom_config} > /var/etc/xray/config_custom.json
}

setup_dnsmasq() {
    utpl /usr/share/xray/dnsmasq_include.ut > /tmp/dnsmasq.d/xray.conf
    logger -st xray[$$] -p4 $(cat /tmp/dnsmasq.d/xray.conf)
    /etc/init.d/dnsmasq restart > /dev/null 2>&1
}

flush_dnsmasq() {
    rm -f /tmp/dnsmasq.d/xray.conf
    /etc/init.d/dnsmasq restart > /dev/null 2>&1
}

create_when_enable() {
    [ "$(uci_get_by_type general transparent_proxy_enable)" == "1" ] || return 0
    logger -st xray[$$] -p4 "Setting dnsmasq and firewall for transparent proxy..."
    setup_dnsmasq
    setup_firewall
    logger -st xray[$$] -p4 $(ucode /usr/share/xray/default_gateway.uc)
}

flush_when_disable() {
    logger -st xray[$$] -p4 "Resetting dnsmasq and firewall configurations..."
    flush_dnsmasq
    flush_firewall
}

start_service() {
    config_load $NAME
    mkdir -p /var/run /var/etc/xray
    local xray_bin=$(uci_get_by_type general xray_bin)
    command -v ${xray_bin} > /dev/null 2>&1 || return 1
    gen_config_file
    start_xray ${xray_bin}
    create_when_enable || flush_when_disable
}

stop_service() {
    flush_when_disable
}

reload_service() {
    stop
    start
}

service_triggers() {
    procd_add_reload_trigger "xray_core"
}
